home *** CD-ROM | disk | FTP | other *** search
- #include<windows.h>
- #include<ctype.h>
- #include"wstring.hpp"
- #include"itemdata.hpp"
-
- #ifdef DEBUG_SCREENS
- extern WinMessageString screen;
- #endif
- extern WinMessageString errscreen;
- extern unsigned int winver;
-
- /////////////////////////////////////
- // defines
- #define CFP(x) (&((char __far *)memptr)[x]) // create char __far * x bytes into buffer
- #define CFP2(x) (&((char __far *)memptr2)[x]) // create char __far * x bytes into buffer
-
- /////////////////////////////////////
- // local data types
-
- struct GroupInfo{
- WORD name;
- WORD executable;
- WORD executable_with_path;
- WORD parameters;
- WORD default_directory;
- WORD minimized;
- };
- struct GroupFileHeader{
- char cIdentifier[4];
- WORD wCheckSum;
- WORD cbGroup;
- WORD nCmdShow;
- RECT rcNormal;
- POINT ptMin;
- WORD pName;
- WORD wLogPixelsX;
- WORD wLogPixelsY;
- BYTE bBitsPerPixel;
- BYTE bPlanes;
- WORD wReserved;
- WORD cItems;
- };
- struct ItemData{
- POINT pt;
- WORD iIcon; // 0 if normal, 1 if minimized
- WORD cbResource;
- WORD cbANDPlane;
- WORD cbXORPlane;
- WORD pHeader;
- WORD pANDPlane;
- WORD pXORPlane;
- WORD pName;
- WORD pCommand;
- WORD pIconPath; // 0 or ptr to initial path
- };
- struct TagData{
- WORD wID;
- WORD wItem;
- WORD cb;
- union{
- char cnext[1];
- int inext;
- }next;
- };
- struct IconHeader{ // pointed to by ItemData.pHeader
- int xHotSpot;
- int yHotSpot;
- int cx; // icon width
- int cy; // icon height
- int cbWidth; // bytes per row including WORD alignment
- BYTE bPlanes; // nbr planes
- BYTE bBitsPixel; // bits per pixel
- };
- /////////////////////////////////////
- // GroupFile member functions
-
- GroupFile::GroupFile(char *p){
- opened=0;
- items_to_read=0;
- tag_bytes=0;
- memhandle=NULL;
- memptr=NULL;
- memhandle2=NULL;
- memptr2=NULL;
- got_icon_default_data=0;
- set_filename(p);
- }
- GroupFile::~GroupFile(){
- if(opened)_lclose(hf);
- if(memhandle!=NULL){
- if(memptr!=NULL)GlobalUnlock(memhandle);
- GlobalFree(memhandle);
- }
- if(memhandle2!=NULL){
- if(memptr2!=NULL)GlobalUnlock(memhandle2);
- GlobalFree(memhandle2);
- }
- #ifdef DEBUG_SCREENS
- screen<<grpfil<<" destructed\n";
- screen.show();
- #endif
- }
- void GroupFile::set_filename(char *p){
- error_condition_exists=(NULL==(grpfil=p))?1:0;
- }
- int GroupFile::openfile(){
- if(error())return 0;
- // assume failure so can just return
- error_condition_exists=1;
- if(opened)return 0;
- opened=((hf=_lopen(grpfil,READ))==HFILE_ERROR)?0:1;
- if(!opened)return 0;
- filebytes=_llseek(hf,0,2); // go to end of file
- if(filebytes==HFILE_ERROR||_llseek(hf,0,0)==HFILE_ERROR)return 0; // go to beginning
- if(filebytes>60000L){
- errscreen<<"Group file is too large. Aborting.\n";
- return 0;
- }
- if(filebytes<(sizeof(GroupFileHeader)+2+sizeof(ItemData)+sizeof(IconHeader))){
- errscreen<<"Group file is empty or too small. Aborting.\n";
- return 0;
- }
- if(NULL==(memhandle=GlobalAlloc(GMEM_FIXED,filebytes))){
- errscreen<<"Could not allocate memory\n";
- return 0;
- }
- if(NULL==(memptr=GlobalLock(memhandle))){
- errscreen<<"Could not lock memory\n";
- return 0;
- }
- if(_lread(hf,memptr,(UINT)filebytes)!=(UINT)filebytes){
- errscreen<<"Could not read group file. Aborting.\n";
- return 0;
- }
- GroupFileHeader __far *p=(GroupFileHeader __far *)memptr;
- if(p->cIdentifier[0]!='P'||p->cIdentifier[1]!='M'||
- p->cIdentifier[2]!='C'||p->cIdentifier[3]!='C'){
- errscreen<<"Group file corrupted. Aborting.\n";
- return 0;
- }
- pItemOffset=(int __far *)&p[1];
- {
- int ok=0;
- for(;;){
- WORD x;
- if(p->cItems<1)break;
- for(x=0;x<p->cItems;x++){
- if(pItemOffset[x]!=0){
- ok=1;
- break;
- }
- }
- break;
- }
- if(!ok){
- errscreen<<"Group file is empty. Aborting.";
- return 0;
- }
- }
- _lclose(hf);
- opened=0;
- error_condition_exists=0;
- return 1;
- }
- void GroupFile::readheader(){
- if(error())return;
- GroupFileHeader _far *p=(GroupFileHeader __far *)memptr;
- // pItemOffset=(int *)&((GroupFileHeader *)memptr)[1];
- items_to_read=p->cItems;
- #ifdef DEBUG_SCREENS
- screen<<"Group name is "<<CFP(p->pName)<<"\n";
- #endif
- // now, if in Win 3.1, associate tag data with items
- // this is because the wItem part of TagData will become
- // invalid (we'll need to sort the icons by position)
- // so we'll use this convention:
- // ItemData == TagData wID usage
- // -------- ----------- -----------------------------
- // iIcon 0x8103 0 if normal, 1 if minimized
- // pIconPath 0x8101 0 or ptr to initial path
- //
- // pseudocode:
- // set all iIcons to 0, pIconPaths to 0
- // if in Windows 3.1 TagData may be present so
- // for each TagData entry
- // apply data to ItemData entry
- // end for
- // end if
- {
- int t;
- ItemData __far *p;
- for(t=0;t<items_to_read;t++){
- if(pItemOffset[t]==0)continue;
- p=(ItemData __far *)CFP(pItemOffset[t]);
- p->iIcon=0;
- p->pIconPath=0;
- }
- }
- if(winver>=0x30A){
- int keep_going=0;
- GroupFileHeader __far *p=(GroupFileHeader __far *)memptr;
- ItemData __far *q;
- TagData __far *tdp;
- if(filebytes>=(LONG)(p->cbGroup+6)){ // '6' sted sizeof(TagData) - sizeof(union)
- tdp=(TagData __far *)CFP(p->cbGroup);
- keep_going=1;
- }
- while(keep_going){
- switch(tdp->wID){
- case 0xFFFF: keep_going=0; break;
- case 0x8101: // path in next.cnext
- q=(ItemData __far *)CFP(pItemOffset[tdp->wItem]);
- q->pIconPath=(WORD)(tdp->next.cnext-(char __far *)memptr);
- break;
- case 0x8103: // app should be minimized
- q=(ItemData __far *)CFP(pItemOffset[tdp->wItem]);
- q->iIcon=1;
- break;
- }
- // '6' in next line is sizeof(TagData) - sizeof(union)
- if((LONG)(((char __far *)tdp-(char __far *)memptr)+tdp->cb+6)>filebytes){
- keep_going=0;
- continue;
- }
- tdp=(TagData __far *)(((char __far *)tdp)+tdp->cb);
- }
- }
- // ok now we can sort the item data by the icon's position
- // so the group looks like it ought to
- // use old'n'lame selection sort but it's good enough here...
- if(items_to_read>1){
- int min,x,left=items_to_read;
- unsigned int temp;
- unsigned int __far *p=(unsigned int __far *)pItemOffset;
- while(left-->1){
- for(x=0,min=0;x<=left;x++)if(second_lower(p[min],p[x]))min=x;
- if(min!=0){temp=p[min];p[min]=*p;*p=temp;}
- p++;
- }
- }
- // now create the compacted version of the file
- // first accumulate target size, then allocate space, then copy space
- unsigned long size=0;
- {
- int left=items_to_read,found_items=0;
- unsigned int __far *p=(unsigned int __far *)pItemOffset;
- ItemData __far *i;
- while(left&&*p){
- i=(ItemData __far *)CFP(*p);
- size+=sizeof(GroupInfo); // space for array entry
- if(i->pName)size+=1+lstrlen(CFP(i->pName)); // space for entry's displayed name
- if(i->pCommand)size+=1+lstrlen(CFP(i->pCommand)); // space for command line
- if(i->pIconPath)size+=1+lstrlen(CFP(i->pIconPath)); // space for command path
- p++;
- left--;
- found_items++;
- }
- items_to_read=found_items; // 'forget' about NULL entries
- }
- // now we know how much memory to get
- // let's get it
- if(size>0)for(;;){
- if(NULL==(memhandle2=GlobalAlloc(GMEM_FIXED,size))){
- errscreen<<"Could not allocate memory for program data\n";
- break;
- }
- if(NULL==(memptr2=GlobalLock(memhandle2))){
- errscreen<<"Could not lock memory for program data\n";
- break;
- }
- // now wind through group file
- // pseudocode: while(items to process)
- // copy data into *gi
- // build and copy strings, put offsets into *gi
- // increment ItemData pointer
- // increment GroupInfo pointer
- GroupInfo __far *gi=(GroupInfo __far *)memptr2;
- char __far *space=(char __far *)&gi[items_to_read]; // point to string space
- int x=items_to_read;
- unsigned int __far *p=(unsigned int __far *)pItemOffset;
- ItemData __far *id;
- char nb1[250],nb2[250];
- while(x--){
- id=(ItemData __far *)CFP(*p);
- gi->minimized=id->iIcon; // GroupInfo.minimized
- gi->name=(WORD)(space-(char __far *)memptr2); // GroupInfo.name
- lstrcpy(space,CFP(id->pName));
- while(*space++); // point past null terminator
- if(id->pCommand!=0)lstrcpy(nb1,CFP(id->pCommand)); // defdir\\exename parms
- else nb1[0]=0;
- if(id->pIconPath!=0)lstrcpy(nb2,CFP(id->pIconPath)); // exepath
- else nb2[0]=0;
- gi->executable_with_path=(WORD)(space-(char __far *)memptr2); // GroupInfo.executable_with_path
- lstrcpy(space,nb2);
- while(*space)space++; // point at null terminator; we'll append .EXE name
- // now find .EXE name
- // first scan off whitespace
- char *nb1_begin=nb1;
- while(isspace(*nb1_begin))nb1_begin++;
- // now go to end of first arg
- char *parms=nb1_begin;
- while(*parms){
- if(isspace(*parms))break;
- parms++;
- }
- // parms points at whitespace between first arg and parameters
- // kill the whitespace
- while(*parms){
- if(isspace(*parms)){
- *parms=0;
- parms++;
- }
- else break;
- }
- // now parms points at the parameters, or a null terminator
- // nb1_begin points at defdir\\exename (whitespace stripped both ends)
- // point exename at executable's name
- char *exename=nb1_begin;
- int got_defdir=0;
- while(*exename)exename++; // point at null terminator
- while(exename>nb1_begin){
- exename--;
- if(*exename=='\\'||*exename==':'){
- got_defdir=(int)(exename-nb1_begin);
- if(exename>nb1_begin&&exename[-1]==':')got_defdir++;
- exename++;
- break; // nb1_begin points at defdir; exename points at executable name
- }
- }
- gi->executable=(WORD)(space-(char __far *)memptr2); // GroupInfo.executable
- lstrcpy(space,exename);
- while(*space++); // point past null terminator
- if(*parms==0)gi->parameters=0; // GroupInfo.parameters
- else{
- gi->parameters=(WORD)(space-(char __far *)memptr2);
- lstrcpy(space,parms);
- while(*space++); // point past null terminator
- }
- if(got_defdir==0)gi->default_directory=0; // GroupInfo.default_directory
- else{
- gi->default_directory=(WORD)(space-(char __far *)memptr2);
- while(got_defdir--)*space++=*nb1_begin++;
- *space++=0; // make null terminator, go past it
- }
- p++;
- gi++;
- }
- break;
- }
- }
- int GroupFile::second_lower(unsigned int first,unsigned int second){
- // compare function for GroupFile::readheader()
- // returns 1 if second should be *before* first
- if(!second)return 0; // it's null, never make it first
- if(!first)return 1; // it's null so second *should* be first
- // now we have two non-NULL entries. Make pointers to item data
- ItemData __far *pfirst=(ItemData __far *)CFP(first);
- ItemData __far *psecond=(ItemData __far *)CFP(second);
- // Which has smaller Y value?
- if(pfirst->pt.y > psecond->pt.y)return 1;
- if(pfirst->pt.y < psecond->pt.y)return 0;
- // OK, depend on X value
- return (pfirst->pt.x > psecond->pt.x)?1:0;
- }
- int GroupFile::showitem(int offset){
- /*
- pseudocode:
- bail out if already failed
- set error_condition_exists to indicate failure
- if read itemdata fails return
- if read
- set error_condition_exists to indicate success
- returns 0 for no item found, 1 for valid item found
- */
- if(error())return 0;
- if(memptr==NULL)return 0;
- if(offset>=items_to_read)return 0;
- if(pItemOffset[offset]==0)return 0; //NULL entry
- ItemData __far *p=(ItemData __far *)CFP(pItemOffset[offset]);
- error_condition_exists=1;
- // set default to failure, so we can just return on error
- #ifdef DEBUG_SCREENS
- screen<<offset<<" "<<CFP(p->pName)<<" ("<<CFP(p->pCommand)<<")\n";
- #endif
- // well, we got here so all must be well
- error_condition_exists=0;
- return 1;
- }
- char __far *GroupFile::get_group_name(){
- if(error())return NULL;
- if(memptr==NULL)return NULL;
- GroupFileHeader __far *p=(GroupFileHeader __far *)memptr;
- if(p->pName==0)return NULL;
- return CFP(p->pName);
- }
- char __far *GroupFile::get_item_name(int offset){
- /*
- returns char * to item name if it's valid (non-null, has printables)
- */
- if(error())return NULL;
- if(memptr2==NULL)return NULL;
- if(offset>=items_to_read)return NULL;
- if(!((GroupInfo __far *)memptr2)[offset].name)return NULL;
- return CFP2(((GroupInfo __far *)memptr2)[offset].name);
- }
- char __far *GroupFile::get_item_command(int offset){
- /*
- returns char * to item's command if it's valid (non-null, has printables)
- */
- if(error())return NULL;
- if(memptr2==NULL)return NULL;
- if(offset>=items_to_read)return NULL;
- if(!((GroupInfo __far *)memptr2)[offset].executable_with_path)return NULL;
- return CFP2(((GroupInfo __far *)memptr2)[offset].executable_with_path);
- }
- char __far *GroupFile::get_item_command_nopath(int offset){
- /*
- returns char * to item's command if it's valid (non-null, has printables)
- */
- if(error())return NULL;
- if(memptr2==NULL)return NULL;
- if(offset>=items_to_read)return NULL;
- if(!((GroupInfo __far *)memptr2)[offset].executable)return NULL;
- return CFP2(((GroupInfo __far *)memptr2)[offset].executable);
- }
- char __far *GroupFile::get_item_parameters(int offset){
- if(error())return NULL;
- if(memptr2==NULL)return NULL;
- if(offset>=items_to_read)return NULL;
- if(!((GroupInfo __far *)memptr2)[offset].parameters)return NULL;
- return CFP2(((GroupInfo __far *)memptr2)[offset].parameters);
- }
- char __far *GroupFile::get_item_default_dir(int offset){
- /*
- returns char * to item's path if it's valid (non-null, has printables)
- */
- if(error())return NULL;
- if(memptr2==NULL)return NULL;
- if(offset>=items_to_read)return NULL;
- if(!((GroupInfo __far *)memptr2)[offset].default_directory)return NULL;
- return CFP2(((GroupInfo __far *)memptr2)[offset].default_directory);
- }
- int GroupFile::is_item_iconized(int offset){
- /*
- returns 1 if item is to be run minimized, 0 if not
- */
- if(error())return 0;
- if(offset>=items_to_read)return NULL;
- if(memptr2!=NULL)return (int)((GroupInfo __far *)memptr2)[offset].minimized;
- if(memptr==NULL)return 0;
- if(pItemOffset[offset]==0)return 0; //NULL entry
- ItemData __far *p=(ItemData __far *)CFP(pItemOffset[offset]);
- return (p->iIcon==0)?0:1;
- }
- HBITMAP GroupFile::get_fill_item_and_bitmap(int offset,int&x,int&y){
- // caller's responsibility to delete bitmap!
- if(error())return NULL;
- if(memptr==NULL)return NULL;
- if(offset>=items_to_read)return NULL;
- if(pItemOffset[offset]==0)return NULL; //NULL entry
- ItemData __far *pID=(ItemData __far *)CFP(pItemOffset[offset]);
- IconHeader __far *pIH=(IconHeader __far *)CFP(pID->pHeader);
- x=pIH->cx;
- y=pIH->cy;
- return CreateBitmap(pIH->cx,pIH->cy,1,1,(const void FAR*)CFP(pID->pANDPlane));
- }
- HBITMAP GroupFile::get_fill_item_xor_bitmap(int offset,int&x,int&y){
- // caller's responsibility to delete bitmap!
- if(error())return NULL;
- if(memptr==NULL)return NULL;
- if(offset>=items_to_read)return NULL;
- if(pItemOffset[offset]==0)return NULL; //NULL entry
- ItemData __far *pID=(ItemData __far *)CFP(pItemOffset[offset]);
- IconHeader __far *pIH=(IconHeader __far *)CFP(pID->pHeader);
- x=pIH->cx;
- y=pIH->cy;
- return CreateBitmap(pIH->cx,pIH->cy,pIH->bPlanes,pIH->bBitsPixel,(const void FAR*)CFP(pID->pXORPlane));
- }
- int GroupFile::get_icon_dimensions(int& height,int& width){
- if(!got_icon_default_data)get_icon_default_data();
- if(!got_icon_default_data){
- height=0x20;
- width=0x20;
- return 1;
- }
- height=y_pixels;
- width=x_pixels;
- return 1;
- }
- UINT GroupFile::get_icon_planes(){
- if(!got_icon_default_data)get_icon_default_data();
- if(!got_icon_default_data)return 4;
- return icon_planes;
- }
- UINT GroupFile::get_icon_pixelbits(){
- if(!got_icon_default_data)get_icon_default_data();
- if(!got_icon_default_data)return 4;
- return icon_pixelbits;
- }
- void GroupFile::done_with_bitmaps(){
- if(memhandle!=NULL){
- if(memptr!=NULL)GlobalUnlock(memhandle);
- GlobalFree(memhandle);
- }
- memhandle=NULL;
- memptr=NULL;
- }
- void GroupFile::get_icon_default_data(){
- HDC ic=CreateIC("DISPLAY",NULL,NULL,NULL);
- if(ic!=NULL){
- x_pixels=GetSystemMetrics(SM_CXICON);
- y_pixels=GetSystemMetrics(SM_CYICON);
- icon_planes=GetDeviceCaps(ic,PLANES);
- icon_pixelbits=GetDeviceCaps(ic,BITSPIXEL);
- got_icon_default_data=1;
- DeleteDC(ic);
- }
- }
-